--[[
    @Author       : baidwwy
    @Date         : 2021-02-11 11:49:09
    @LastEditTime : 2021-03-02 16:15:17
--]]

local adler32       = require("zlib").adler32
local m_pack        = require("cmsgpack").pack
local m_unpack      = require("cmsgpack.safe").unpack

local c_isyieldable = coroutine.isyieldable
local c_runing      = coroutine.running
local c_yield       = coroutine.yield
local c_resume      = coroutine.resume
local c_create      = coroutine.create
local t_unpack      = table.unpack
local PackAgent = package.loaded.PackAgent or  require("HPS/PackAgent")
local RPCAgent = class("RPCAgent",PackAgent)

local REG = setmetatable({}, {__mode="k"})
local CB  = setmetatable({}, {__mode="k"})


function RPCAgent:RPCAgent()
    PackAgent.PackAgent(self)--初始化父类
    local reg = {}
    REG[self] = reg--private
    CB[self]  = {}--private
    
    return setmetatable({}, {
        __newindex = function ( t,k,v )
            if type(v)=="function" then
                reg[k] = v
                reg[adler32(k)] = v
            end
        end,
        __index = reg
    })
end

function RPCAgent:__index(k,super)--调用方法
    local co,main = c_runing()
    local hash = adler32(k)
    if co and not main and c_isyieldable() then--如果有协程，则有返回值
        return function (self,id,...)
            if id then
                local cp = adler32(tostring(co))
                CB[self][cp] = co
                self._hp:Send(id,m_pack{hash,cp,...})
                return c_yield()
            end
        end
    end
    return function (self,id,...)
        if id then
            self._hp:Send(id,m_pack{hash,0,...})
        end
    end
end

function RPCAgent:发送(id,...)
    return self._hp:Send(id,m_pack{...})
end

local function cofunc(self,id,cp,func,...)
    self._hp:Send(id,m_pack{0,cp,func(self,id,...)})
end

function RPCAgent:_数据事件(id,data)
    local t = m_unpack(data)
    if type(t)=='table' then
        local hash,cp = t[1],t[2]
        if hash==0 then--返回
            local co = CB[self][cp]
            if co then
                CB[self][cp] = nil
                local r,err = c_resume(co, t_unpack(t,3))
                if not r then
                    warn(err)
                end
            end
        else
            local func = REG[self][hash]
            if func then
                if cp==0 then--没有返回
                    func(self,id,t_unpack(t,3))
                else
                    local co = c_create(cofunc)
                    local r,err = c_resume(co,self,id,cp,func,t_unpack(t,3))
                    if not r then
                        warn(err)
                        self._hp:Send(id,m_pack{0,cp,nil})
                    end
                end
            elseif co~=0 then
                self._hp:Send(id,m_pack{0,cp,nil})
            end
        end
    elseif self.数据事件 then
        self:数据事件(id,data)
    end
end

return RPCAgent